/**
 * 
 */
package edu.cmu.mism.dgjava.data.ui.tree;

import org.eclipse.draw2d.ChopboxAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.PolylineDecoration;
import org.eclipse.draw2d.ScrollPane;
import org.eclipse.draw2d.ScrollPaneLayout;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import edu.cmu.mism.dgjava.algorithm.impl.TreeNode;

/**
 * @author Christian
 * 
 */
public class TreeDialog {

	private TreeNode[][] model;
	private TreeNodeFigure[][] tree;

	private static final int HORIZONTAL_PADDING = 25;
	private static final int DEFAULT_WIDTH = 80;
	private static final int DEFAULT_HEIGHT = 35;
	private static final int MARGIN = 12;
	private static final int SHELL_SIZE_ADJUSTMENT_H = 16;
	private static final int SHELL_SIZE_ADJUSTMENT_V = 12;

	public TreeDialog(TreeNode[][] model) {
		this.model = model;
		this.tree = new TreeNodeFigure[model.length][model[0].length];

	}

	public void open() {

		Display d = Display.getDefault();
		final Shell shell = new Shell(d);
		shell.setLayout(new FillLayout());

		shell
				.setSize(
						(2 * MARGIN + model.length
								* (DEFAULT_WIDTH + SHELL_SIZE_ADJUSTMENT_H) + (model.length - 1)
								* MARGIN),
						((2 * MARGIN + model.length
								* (DEFAULT_HEIGHT + SHELL_SIZE_ADJUSTMENT_V) + (model.length - 1)
								* (DEFAULT_HEIGHT))));

		shell.setText("Option Price Binomial Tree");
		shell.setBackground(d.getSystemColor(SWT.COLOR_WHITE));

		
		LightweightSystem lws = new LightweightSystem(shell);
		ScrollPane sp = new ScrollPane();
		sp.setLayoutManager(new ScrollPaneLayout());

		Figure contents = new Figure();
		XYLayout contentsLayout = new XYLayout();
		contents.setLayoutManager(contentsLayout);

		createTreeDisplay(contents, contentsLayout);

		sp.setContents(contents);
		lws.setContents(sp);

		shell.open();
		while (!shell.isDisposed())
			while (!d.readAndDispatch())
				d.sleep();
	}

	private void createTreeDisplay(Figure contents, XYLayout contentsLayout) {
		int s_x = MARGIN;

		int s_y = ((2 * MARGIN + (2 * model.length - 1) * DEFAULT_HEIGHT) / 2)
				- (DEFAULT_HEIGHT / 2);

		// setting up the root node
		TreeNodeFigure rf = new TreeNodeFigure(model[0][0]);
		tree[0][0] = rf;
		contentsLayout.setConstraint(rf, new Rectangle(s_x, s_y, DEFAULT_WIDTH,
				DEFAULT_HEIGHT));
		contents.add(rf);

		// creating its children
		for (int r = 1; r < model.length; r++) {
			int t_y = s_y + r * DEFAULT_HEIGHT;
			int t_x = s_x + r * (DEFAULT_WIDTH + HORIZONTAL_PADDING);
			for (int c = 0; c < model[r].length; c++) {
				if (model[r][c] != null) {
					// adjusting t_y
					TreeNodeFigure tf = new TreeNodeFigure(model[r][c]);
					contentsLayout.setConstraint(tf, new Rectangle(t_x, t_y - c
							* (2 * DEFAULT_HEIGHT), DEFAULT_WIDTH,
							DEFAULT_HEIGHT));
					contents.add(tf);
					tree[r][c] = tf;
				}
			}
		}

		setupConnection(contents);
	}

	private void setupConnection(Figure contents) {
		for (int r = 0; r < tree.length - 1; r++) {
			for (int c = 0; c < tree[r].length; c++) {
				if (tree[r][c] != null) {
					contents.add(createConnection(tree[r][c], tree[r + 1][c]));
					contents.add(createConnection(tree[r][c],
							tree[r + 1][c + 1]));
				}
			}
		}
	}

	private PolylineConnection createConnection(TreeNodeFigure source,
			TreeNodeFigure target) {
		/* Creating the connection */

		PolylineConnection conn = new PolylineConnection();
		ChopboxAnchor sourceAnchor = new ChopboxAnchor(source);
		ChopboxAnchor targetAnchor = new ChopboxAnchor(target);
		conn.setSourceAnchor(sourceAnchor);
		conn.setTargetAnchor(targetAnchor);

		/* Creating the decoration */
		PolylineDecoration decoration = new PolylineDecoration();
		conn.setTargetDecoration(decoration);

		return conn;
	}

}
